﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////

//*C# style String.Format()*/
#pragma once

#include "GcmpApiFoundation.h"
#include "StringUtil.h"
#include <sstream>
#include <string>
#include <regex>

namespace gdmp
{
    namespace api
    {
        namespace detail
        {
            template <typename T>
            std::string str(const T& rhs)
            {
                std::stringstream ss;
                ss << rhs;
                return ss.str();
            }
            GCMP_API_FOUNDATION_EXPORT inline std::string str(const char* rhs) { return std::string{ rhs }; }

            template<int N>
            struct Format
            {
                template<typename ... Args>
                static std::string parse(const std::string& format, const std::tuple<Args...>& args)
                {
                    constexpr int INDEX = N - 1;
                    std::stringstream ss;
                    ss << "\\{" << INDEX << "\\}(?!\\})";
                    std::regex pattern{ ss.str().c_str() };
                    return Format<INDEX>::parse(std::regex_replace(format, pattern, str(std::get<INDEX>(args))), args);
                }
            };

            template<>
            struct Format<0>
            {
                template<typename ... Args>
                static std::string parse(const std::string& format, const std::tuple<Args...>& args)
                {
                    // check if exists invalid {N}
                    static const std::regex pattern{ "\\{[0-9]+\\}(?!\\})" };
                    std::smatch match;
                    if (std::regex_search(format, match, pattern)) {
                        throw std::invalid_argument("索引(从零开始)必须大于或等于零，且小于参数列表的大小。");
                    }
                    // relace {{}} to {}
                    static const std::regex replacePattern{ "\\{(\\{+[0-9]+\\}+)\\}" };
                    return  std::regex_replace(format, replacePattern, "$1");
                }
            };
        }


        //C# style String.Format()
        template <typename ... Args>
        std::string sformat(const char* format, const Args& ... args)
        {
            const auto tuple = std::forward_as_tuple(args...);
            constexpr size_t SIZE = sizeof...(args);
            return detail::Format<SIZE>::parse(format, tuple);
        }

        GCMP_API_FOUNDATION_EXPORT inline std::string sformat(const char* format) { return format; }
    }
}

/**
  C# style String.Format()

  **Example**::
    #include "ApiStringFormat.h"

    int a = 50;
    int b = 10;
    std::string message = FMT("a + b = {0}", a+b);

    output: a + b = 60
*/
#define FMT(format, ...)  gdmp::api::sformat(format,__VA_ARGS__)
#define WFMT(format, ...)  gcmp::StringUtil::ToWStringByCodeType(FMT(format,__VA_ARGS__),gcmp::StringUtil::EnCodeType::CT_ANSI)

#define WFMT_TR(format, ...) GBMP_TR(WFMT(format,__VA_ARGS__))
#define FMT_TR(format, ...) gcmp::StringUtil::ToStringByCodeType(WFMT_TR(format,__VA_ARGS__),gcmp::StringUtil::EnCodeType::CT_ANSI)
